package com.cloudfast.oauth.granter;

import java.util.LinkedHashMap;
import java.util.Map;

import org.springframework.security.authentication.AbstractAuthenticationToken;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.oauth2.provider.ClientDetails;
import org.springframework.security.oauth2.provider.ClientDetailsService;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.OAuth2Request;
import org.springframework.security.oauth2.provider.OAuth2RequestFactory;
import org.springframework.security.oauth2.provider.TokenRequest;
import org.springframework.security.oauth2.provider.token.AbstractTokenGranter;
import org.springframework.security.oauth2.provider.token.AuthorizationServerTokenServices;

import com.cloudfast.context.error.CloudException;
import com.cloudfast.context.error.ErrorCode;
import com.cloudfast.dingtalk.CloudDingTalk;
import com.cloudfast.oauth.feign.UserCenterFeignService;
import com.cloudfast.platform.app.AppClient;

/**
 * 钉钉免密登入
 *
 * @author liuyw
 * @date 2022年9月10日
 */
public class DingTokenGranter extends AbstractTokenGranter {

    private static final String GRANT_TYPE = "ding";

    /**
     * 查询用户信息
     */
    private UserDetailsService userDetailsService;

    private UserCenterFeignService feignService;

    private CloudDingTalk cloudDingTalk;

    public DingTokenGranter(AuthenticationManager authenticationManager,
                            /**
                             * 默认tokenServices
                             */
                            AuthorizationServerTokenServices tokenServices,
                            /**
                             * 默认客户端services
                             */
                            ClientDetailsService clientDetailsService,

                            /**
                             * requestFactory
                             */
                            OAuth2RequestFactory requestFactory,

                            /**
                             * userDetailsService
                             */
                            UserDetailsService userDetailsService, /**
                             * feignService
                             */
                            UserCenterFeignService feignService

    ) {
        this(authenticationManager, tokenServices, clientDetailsService, requestFactory, GRANT_TYPE);
        this.userDetailsService = userDetailsService;
        this.feignService = feignService;
        cloudDingTalk = new CloudDingTalk();

    }

    protected DingTokenGranter(AuthenticationManager authenticationManager,
                               AuthorizationServerTokenServices tokenServices, ClientDetailsService clientDetailsService,
                               OAuth2RequestFactory requestFactory, String grantType) {
        super(tokenServices, clientDetailsService, requestFactory, grantType);
    }

    @Override
    protected OAuth2Authentication getOAuth2Authentication(ClientDetails client, TokenRequest tokenRequest) {

        Map<String, String> parameters = new LinkedHashMap<>(tokenRequest.getRequestParameters());

        /**
         * 钉钉认证code
         */
        String dingCode = parameters.get("dingCode");

        /**
         * 钉钉企业corpId
         */
        String corpId = parameters.get("corpId");

        /**
         * 钉钉企业识别名称
         */
        String appLabel = parameters.get("appLabel");

        /**
         * 调用app信息
         */
        AppClient appClient = feignService.findAppClientByLabel(appLabel, corpId, "ding");
        if (appClient != null) {
            // 获取accessToken
            String accessToken = cloudDingTalk.getAccessToken(appClient.getCorpId(), appClient.getAppKey(),
                    appClient.getAppSecret(), appClient.getAppTicket(), appClient.getAppScope());
            Map<String, Object> userInfo = cloudDingTalk.getUserInfoByTempCode(dingCode, accessToken);
            System.err.println("钉钉用户:" + userInfo);
            String username = userInfo.get("userid").toString();
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            if (userDetails != null) {
                Authentication userAuth = new UsernamePasswordAuthenticationToken(userDetails,
                        userDetails.getPassword(), userDetails.getAuthorities());
                ((AbstractAuthenticationToken) userAuth).setDetails(parameters);

                OAuth2Request storedOAuth2Request = getRequestFactory().createOAuth2Request(client, tokenRequest);
                return new OAuth2Authentication(storedOAuth2Request, userAuth);
            }
            throw new CloudException(ErrorCode.NO_USER_INFO);

        }

        throw new CloudException(ErrorCode.NO_USER_INFO);

    }

}
